<template>
    <div class="info-box">
        <div class="top-box">
            <div class="back-btn" @click="backIndex">返回列表</div>
            <el-select v-model="value" placeholder="请选择...">
                <el-option key="item.value" label="item.label" value="item.value" />
            </el-select>
            <div class="full-screen">
                <img src="@/assets/fullscreen.png" alt="">
                <span>全屏</span>
            </div>
        </div>
        <div ref="graphContainer" class="graph-container"></div>
        <div class="left-box">
            <div class="point-box">
                <div class="point-list">
                    <span>知识点</span>
                    <span>302</span>
                </div>
                <div class="point-list">
                    <span>知识关系</span>
                    <span>489</span>
                </div>
                <div class="point-list">
                    <span>思政点</span>
                    <span>23</span>
                </div>
                <div class="point-list">
                    <span>考点</span>
                    <span>53</span>
                </div>
                <div class="point-list">
                    <span>难点</span>
                    <span>32</span>
                </div>
                <div class="point-list">
                    <span>重点</span>
                    <span>64</span>
                </div>
                <div class="point-list">
                    <span>资源</span>
                    <span>135</span>
                </div>
                <div class="point-list">
                    <span>习题</span>
                    <span>29</span>
                </div>
            </div>
        </div>
        <div class="right-box desc-item" v-if="formShow">
            <div class="point-box">
            <div class="desc-title">编辑知识点</div>
                <div class="point-list">
                    <div class="items">
                        <div class="text">所属项目/任务</div>
                        <div class="reds">*</div>
                    </div>
                    <div class="inputs">
                        <el-select v-model="value" class="m-2" placeholder="请选择所属项目/任务">
                            <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
                        </el-select>
                    </div>
                </div>
                <div class="point-list">
                    <div class="items">
                        <div class="text">知识点名称</div>
                        <div class="reds">*</div>
                    </div>
                    <div class="inputs">
                        <el-input v-model="input" placeholder="请输入知识点名称" />
                    </div>
                </div>
                <div class="point-list">
                    <div class="items">
                        <div class="text">知识点类型</div>
                    </div>
                    <div class="points">
                        <div class="chapter-icon orange">重点</div>
                        <div class="chapter-icon orange">重点</div>
                        <div class="chapter-icon orange">重点</div>
                    </div>
                </div>
                <div class="point-list">
                    <div class="items">
                        <div class="text">思政点标识</div>
                        <div class="reds">*</div>
                    </div>
                    <div class="class-switch">
                        <div class="slider" :class="{'mode-1': politics === 0, 'mode-2': politics === 1}"  :style="politicsStyle"></div>
                        <div class="switch-item" :class="{active: politics === 0}" @click="politics = 0">知识点</div>
                        <div class="switch-item" :class="{active: politics === 1}" @click="politics = 1">思政点</div>
                    </div>
                </div>
                <div class="point-list">
                    <div class="items">
                        <div class="text">对应课程目标</div>
                        <div class="reds">*</div>
                    </div>
                    <div class="inputs">
                        <el-select v-model="value" class="m-2" placeholder="请选择对应课程目标">
                            <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
                        </el-select>
                    </div>
                </div>
                <div class="point-list">
                    <div class="items">
                        <div class="text">知识点描述</div>
                    </div>
                    <div class="inputs">
                        <Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
                        <Editor style="text-align: left;padding-bottom: 20px;" v-model="valueHtml" :defaultConfig="editorConfig" :mode="mode" @onCreated="handleCreated" />
                    </div>
                </div>
            </div>
        </div>
        <div class="right-box desc-item" v-if="descShow">
            <el-scrollbar height="700px">
                <div class="point-box desc-box">
                    <div class="desc-title desc-title">
                            <span>知识点详情</span>
                            <div class="points">
                                <div class="chapter-icon">重点</div>
                                <div class="chapter-icon orange">重点</div>
                                <div class="chapter-icon orange">重点</div>
                            </div>
                    </div>
                    <div class="point-list">
                        <div class="items">
                            <div class="text">知识点名称</div>
                        </div>
                        <div class="desc">
                            <div class="text">知识点内容占位知识点内容占位知识点内容占位知识点内容占位知识点内容占位知识点内容占位知识点内容占位知识点内容占位知识点内容占位知识点内容占位知识点内容占位知识点内容占位知识点内容占位知识点内容占位知识点内容占位知识点内容占位。</div>
                        </div>
                    </div>
                    <div class="point-list">
                        <div class="items">
                            <div class="text">所在项目/任务</div>
                        </div>
                        <div class="desc">
                            <div class="text">1. 项目/任务名称占位项目/任务名称占位。</div>
                            <div class="text">2. 项目/任务名称占位项目/任务名称占位。</div>
                        </div>
                    </div>
                    <div class="point-list">
                        <div class="items">
                            <div class="text">对应课程目标</div>
                        </div>
                        <div class="desc">
                            <div class="text">1. 对应课程目标内容占位对应课程目标内容占位。
        2. 对应课程目标内容占位对应课程目标内容占位对应课程目标内容占位对应课程目标内容占位。</div>
                        </div>
                    </div>
                    <div class="point-list">
                        <div class="items">
                            <div class="text">知识关系</div>
                        </div>
                        <div class="desc-table">
                            <div class="table-item">
                                <div class="tab-head">关系</div>
                                <div class="tab-head">知识点</div>
                            </div>
                            <div class="table-item tab-content" v-for="(item,index) in classItem" :key="index">
                                <div>{{ item.title }}</div>
                                <div>{{ item.desc }}</div>
                            </div>
                        </div>
                    </div>
                    <div class="point-list">
                        <div class="items">
                            <div class="text">知识点资源（0）</div>
                        </div>
                        <div class="desc">
                            <div class="text">暂无知识点资源</div>
                        </div>
                    </div>
                    <div class="point-list">
                        <div class="items">
                            <div class="text">考题/习题（0）</div>
                        </div>
                        <div class="desc">
                            <div class="text">暂无考题/习题</div>
                        </div>
                    </div>
                    <div class="point-list" @click="descShow = false">
                        <el-button>关闭</el-button>
                    </div>
                </div>
            </el-scrollbar>
        </div>
        <div class="right-box desc-item" v-if="addLineShow" style="top: 20%;">
            <el-scrollbar height="500px" class="point-box desc-box">
                <div class="desc-title desc-title">
                    <span>新增关系线</span>
                </div>
                <div class="point-list">
                    <div class="items">
                        <div class="text">起始知识点：强化学习的应用</div>
                    </div>
                    <div class="notices">
                        <div class="top-notice">
                            <img src="@/assets/notice.png" alt="">
                            <span>温馨提示</span>
                        </div>
                        <div class="notice-content">
                            <span class="title">方式一：图谱关联</span>
                            <span class="desc">在图谱中点击知识点进行关联。</span>
                        </div>
                        <div class="notice-content">
                            <span class="title">方式二：筛选关联</span>
                            <span class="desc">在筛选栏中选择知识点名称(单选)</span>
                        </div>
                    </div>
                </div>
                <div class="point-list">
                    <div class="items">
                        <div class="text">连接线名称</div>
                        <div class="reds">*</div>
                    </div>
                    <div class="inputs">
                        <el-select v-model="value" class="m-2" placeholder="请选择连接线（自定义输入通过回车确认）">
                            <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
                        </el-select>
                    </div>
                </div>
                <div class="point-list">
                    <div class="items">
                        <div class="text">目标知识点</div>
                        <div class="reds">*</div>
                    </div>
                    <div class="inputs">
                        <el-select v-model="value" class="m-2" placeholder="请选择/输入目标知识点">
                            <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
                        </el-select>
                    </div>
                </div>
                <div class="point-list submit">
                    <el-button @click="addLineShow = false">关闭</el-button>
                    <el-button type="primary" class="save">保存</el-button>
                </div>
            </el-scrollbar>
        </div>
        <div class="right-box desc-item" v-if="edntColorShow" style="top: 30%;">
            <el-scrollbar height="350px" class="point-box desc-box">
                <div class="desc-title desc-title">
                    <span>编辑颜色</span>
                </div>
                <div class="point-list">
                    <div class="items">
                        <div class="text">项目/章名称</div>
                        <div class="reds">*</div>
                    </div>
                    <div class="inputs">
                        <el-select v-model="value" class="m-2" placeholder="请选择项目/章名称">
                            <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
                        </el-select>
                    </div>
                </div>
                <div class="point-list">
                    <div class="items">
                        <div class="text">选择颜色</div>
                        <div class="reds">*</div>
                    </div>
                    <div class="inputs">
                        <div class="preset-colors">
                            <div v-for="(color, index) in presetColors" :key="index" class="color-block" :style="{ backgroundColor: color }" @click="selectPresetColor(color)">
                                <div v-if="selectedColor === color" class="color-check"></div>
                            </div>
                        </div>
                        <div class="color-controls">
                            <div class="color-preview" :style="{ backgroundColor: currentHex }" ></div>
                            <div class="color-box">
                                <span>Hex</span>
                                <el-input v-model="hexInput" @input="handleHexInput" />
                            </div>
                        </div>
                    </div>
                </div>
                <div class="point-list submit">
                    <el-button @click="addLineShow = false">关闭</el-button>
                    <el-button type="primary" class="save">保存</el-button>
                </div>
            </el-scrollbar>
        </div>
        <div class="menu-box">
            <div class="menu-div">
                <div class="menu-item">
                    <img src="@/assets/menu/edit-konw.png" alt="">
                </div>
                <div class="menu-item">
                    <img src="@/assets/menu/know-desc.png" alt="">
                </div>
                <div class="menu-item">
                    <img src="@/assets/menu/add-line.png" alt="">
                </div>
                <div class="menu-item">
                    <img src="@/assets/menu/dele-know.png" alt="">
                </div>
            </div>
        </div>
        <el-dialog v-model="delePointShow" width="20%" top="35vh">
            <template #header>
                <div class="headers">
                    <img src="@/assets/tishi.png" alt="">
                    <span>提示</span>
                </div>
            </template>
            <div class="dialog-content">
                <span>此操作将永久删除《知识点内容占位》，是否继续?</span>
            </div>
            <template #footer>
                <span class="dialog-footer">
                    <el-button @click="delePointShow = false"> 取消 </el-button>
                    <el-button type="primary" @click="delePointShow = false"> 确认 </el-button>
                </span>
            </template>
        </el-dialog>

        <el-popover ref="pointShowRef" popper-class="graph-box" :virtual-ref="addPointRef" trigger="click" virtual-triggering >
            <div class="popover-box">
                <span>手动添加知识点</span>
                <span>教材导入知识点</span>
            </div>
        </el-popover>
    </div>
</template>

<script>
    import * as d3 from 'd3';
    export default {
        name: 'Neo4jGraph',
        data() {
            return {
            graphData: {
                nodes: [],
                links: []
            },
            filteredData: {
                nodes: [],
                links: []
            },
            rootNodes: [],
            selectedRoot: 'all',
            simulation: null,
            svg: null,
            selectedNode: null,
            selectedRing: null,
            selectedLink: null,
            zoom: null,
            g: null,
            options : [ { value: 'Option1', label: 'Option1', }, { value: 'Option2', label: 'Option2', }, { value: 'Option3', label: 'Option3', }, { value: 'Option4', label: 'Option4', }, { value: 'Option5', label: 'Option5', }, ]
            };
            
        },
        mounted() {
            this.generateMockData();
            this.initGraph();
            
        },
        methods: {
            generateMockData() {
                // 生成10个根节点
                for (let i = 1; i <= 10; i++) {
                    this.graphData.nodes.push({
                        id: `root${i}`,
                        name: `根节点${i}`,
                        group: i,
                        isRoot: true
                    });
                    
                    // 为每个根节点生成5-10个子节点
                    const childCount = Math.floor(Math.random() * 6) + 5;
                    for (let j = 1; j <= childCount; j++) {
                        this.graphData.nodes.push({
                        id: `node${i}-${j}`,
                        name: `子节点${i}-${j}`,
                        group: i,
                        isRoot: false
                        });
                    }
                }

                // 生成关系 - 确保箭头方向从根节点指向子节点
                this.graphData.nodes.forEach(node => {
                    if (!node.isRoot) {
                        // 子节点连接到根节点（箭头方向从根节点指向子节点）
                        const rootId = `root${node.group}`;
                        this.graphData.links.push({
                        id: `link-${rootId}-${node.id}`,
                        source: rootId,  // 源是根节点
                        target: node.id, // 目标是子节点
                        value: Math.floor(Math.random() * 10) + 1,
                        relation: '包含'
                        });

                        // 子节点间连接（如果有）
                        if (Math.random() > 0.7) {
                        const siblings = this.graphData.nodes
                            .filter(n => n.group === node.group && n.id !== node.id && !n.isRoot);
                            if (siblings.length > 0) {
                                const randomSibling = siblings[Math.floor(Math.random() * siblings.length)];
                                this.graphData.links.push({
                                id: `link-${node.id}-${randomSibling.id}`,
                                source: node.id,
                                target: randomSibling.id,
                                value: Math.floor(Math.random() * 10) + 1,
                                relation: ['依赖', '关联', '引用'][Math.floor(Math.random() * 3)]
                                });
                            }
                        }
                    }
                });

                this.rootNodes = this.graphData.nodes.filter(node => node.isRoot);
            },
            initGraph() {
                const container = this.$refs.graphContainer;
                const width  = container.clientWidth;
                const height = container.clientHeight;

                if (this.svg) {
                    this.svg.remove();
                }

                this.svg = d3.select(container)
                    .append('svg')
                    .attr('width', width)
                    .attr('height', height);

                this.zoom = d3.zoom()
                    .scaleExtent([0.1, 8])
                    .on('zoom', (event) => {
                    this.g.attr('transform', event.transform);
                    });

                this.svg.call(this.zoom);
                this.g = this.svg.append('g');
                this.showAllGraph();
            },
            showAllGraph() {
            this.filteredData.nodes = [...this.graphData.nodes];
            this.filteredData.links = [...this.graphData.links];
            this.createForceGraph();
            },
            filterGraph() {
                if (this.selectedRoot === 'all') {
                    this.showAllGraph();
                    return;
                }
                console.log(this.graphData)
                this.filteredData.nodes = [];
                this.filteredData.links = [];

                // 添加选中的根节点
                const rootNode = this.graphData.nodes.find(node => node.id === this.selectedRoot);
                this.filteredData.nodes.push(rootNode);

                // 查找所有关联节点（使用BFS算法）
                const visitedNodes = new Set([this.selectedRoot]);

                const queue = [this.selectedRoot];
                
                while (queue.length > 0) {
                const currentNode = queue.shift();
                
                // 查找所有以当前节点为起点的关系
                const connectedLinks = this.graphData.links.filter(link => 
                    link.source === currentNode || link.target === currentNode
                );

                connectedLinks.forEach(link => {
                    // 添加关系
                    if (!this.filteredData.links.some(l => l.id === link.id)) {
                    this.filteredData.links.push(link);
                    }

                    // 获取相连节点ID
                    const otherNodeId = link.source === currentNode ? link.target : link.source;
                    
                    // 如果节点未访问过，则添加到队列和节点列表
                    if (!visitedNodes.has(otherNodeId)) {
                    visitedNodes.add(otherNodeId);
                    queue.push(otherNodeId);
                    
                    const otherNode = this.graphData.nodes.find(node => node.id === otherNodeId);
                    this.filteredData.nodes.push(otherNode);
                    }
                });
                }

                this.createForceGraph();
            },
            createForceGraph() {
            if (this.simulation) {
                this.simulation.stop();
            }

            this.g.selectAll('*').remove();

            // 创建力导向图
            this.simulation = d3.forceSimulation(this.filteredData.nodes)
                .force('link', d3.forceLink(this.filteredData.links).id(d => d.id).distance(100))
                .force('charge', d3.forceManyBody().strength(-300))
                .force('center', d3.forceCenter(this.svg.attr('width') / 2, this.svg.attr('height') / 2));

            // 创建箭头定义
            const defs = this.g.append('defs');
            
            defs.append('marker')
                .attr('id', 'arrowhead')
                .attr('viewBox', '0 -5 10 10')
                .attr('refX', 18)
                .attr('refY', 0)
                .attr('markerWidth', 6)
                .attr('markerHeight', 6)
                .attr('orient', 'auto')
                .append('path')
                .attr('d', 'M0,-5L10,0L0,5')
                .attr('fill', '#000');

            // 创建连线
            const link = this.g.append('g')
                .selectAll('line')
                .data(this.filteredData.links)
                .enter().append('line')
                .attr('class', 'link')
                .attr('stroke', '#999')
                .attr('stroke-width', 1)
                .attr('stroke-dasharray', '3,3')
                .attr('marker-end', 'url(#arrowhead)')
                .on('click', (event, d) => this.handleLinkClick(event, d));

            // 创建关系文字
            const linkText = this.g.append('g')
                .selectAll('text')
                .data(this.filteredData.links)
                .enter().append('text')
                .attr('class', 'link-text')
                .attr('font-size', 10)
                .attr('fill', '#000')
                .text(d => d.relation || d.target.name);

            // 创建节点
            const node = this.g.append('g')
                .selectAll('g.node')
                .data(this.filteredData.nodes)
                .enter().append('g')
                .attr('class', 'node')
                .style('cursor', 'pointer')
                .call(d3.drag()
                .on('start', this.dragstarted)
                .on('drag', this.dragged)
                .on('end', this.dragended));

            // 节点圆圈
            node.append('circle')
                .attr('r', d => {
                if (this.selectedRoot === 'all') {
                    return d.isRoot ? 25 : 20;
                } else {
                    return d.id === this.selectedRoot ? 30 : 20;
                }
                })
                .attr('fill', d => {
                const colors = ['#66c2a5', '#fc8d62', '#8da0cb','#66c2a5', '#fc8d62', '#8da0cb','#66c2a5', '#fc8d62', '#8da0cb', '#8da0cb'];
                return colors[d.group - 1];
                })
                .on('click', (event, d) => this.handleNodeClick(event, d));

            // 节点文字
            const nodeText = node.append('text')
                .attr('dy', 4)
                .attr('text-anchor', 'middle')
                .attr('fill', 'white')
                .style('font-size', d => {
                if (this.selectedRoot === 'all') {
                    return d.isRoot ? '10px' : '8px';
                } else {
                    return d.id === this.selectedRoot ? '10px' : '8px';
                }
                })
                .style('dominant-baseline', 'auto')
                .text(d => {
                const maxLength = 4;
                return d.name.length > maxLength ? 
                    d.name.substring(0, maxLength) + '...' : 
                    d.name;
                });
            // 应用文字
            nodeText.attr('clip-path', d => `url(#clip-${d.id})`);
            // 更新函数
            const ticked = () => {
                link
                .attr('x1', d => d.source.x)
                .attr('y1', d => d.source.y)
                .attr('x2', d => d.target.x - (d.target.x - d.source.x) * 15 / Math.sqrt(Math.pow(d.target.x - d.source.x, 2) + Math.pow(d.target.y - d.source.y, 2)))
                .attr('y2', d => d.target.y - (d.target.y - d.source.y) * 15 / Math.sqrt(Math.pow(d.target.x - d.source.x, 2) + Math.pow(d.target.y - d.source.y, 2)));

                linkText
                .attr('x', d => (d.source.x + d.target.x) / 2)
                .attr('y', d => (d.source.y + d.target.y) / 2);

                node.attr('transform', d => `translate(${d.x},${d.y})`);
                
                if (this.selectedRing && this.selectedNode) {
                this.selectedRing
                    .attr('cx', this.selectedNode.x)
                    .attr('cy', this.selectedNode.y);
                }
            };

            this.simulation.on('tick', ticked);
            },
            handleNodeClick(event, d) {
            if (this.selectedRing) {
                this.selectedRing.remove();
            }

            const color = d3.select(event.currentTarget).attr('fill');
            
            this.selectedRing = this.g.append('circle')
                .attr('class', 'selected-ring')
                .attr('cx', d.x || 0) 
                .attr('cy', d.y || 0) 
                .attr('r', () => {
                if (this.selectedRoot === 'all') {
                    return d.isRoot ? 30 : 25;
                } else {
                    return d.id === this.selectedRoot ? 35 : 25;
                }
                })
                .attr('fill', 'none')
                .attr('stroke', color)
                .attr('stroke-width', 2)
                .attr('stroke-dasharray', '5,5');
            
            this.selectedNode = d;
            },
            handleLinkClick(event) {
            if (this.selectedLink) {
                this.selectedLink.attr('stroke-dasharray', '3,3');
                this.selectedLink.attr('stroke', '#999');
            }
            
            this.selectedLink = d3.select(event.currentTarget)
                .attr('stroke-dasharray', null)
                .attr('stroke', '#000000');
            },
            dragstarted(event, d) {
            if (!event.active) this.simulation.alphaTarget(0.3).restart();
                d.fx = d.x;
                d.fy = d.y;
            },
            dragged(event, d) {
                d.fx = event.x;
                d.fy = event.y;
            },
            dragended(event, d) {
                if (!event.active) this.simulation.alphaTarget(0);
                d.fx = null;
                d.fy = null;
            },
        }
    };
</script>
<script setup>
    import { ref, shallowRef,onBeforeUnmount,computed,reactive,defineEmits } from 'vue'
    import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
    import '@wangeditor/editor/dist/css/style.css'
    const politics   = ref(0)
    const editorRef  = shallowRef();
    const valueHtml  = ref("<p>初始内容</p>");
    const formShow   = ref(false)
    const descShow   = ref(false)
    const addLineShow = ref(false)
    const edntColorShow = ref(true)
    const delePointShow = ref(false)
    const addPointRef  = ref()
    const pointShowRef = ref()
    const selectedColor = ref('#FF0000');
    const hexInput = ref('#FF0000');
    const classItem = ref([
        {
            'title':'学校/机构',
            'desc':'启原科技大学',
        },
        {
            'title':'课程类型',
            'desc':'专业基础课',
        },
        {
            'title':'课程状态',
            'desc':'未发布',
        },
        {
            'title':'授课方式',
            'desc':'章节式教学',
        },
        {
            'title':'前置课程',
            'desc':'暂无',
        },
        {
            'title':'课程教师',
            'desc':'刘莹昕',
        }
    ])

    const currentHex = computed(() => {
        return hsvToHex(hsv.h, hsv.s, hsv.v);
    });
    const presetColors = ref([
        '#DB98F5', '#9289FC ', '#89B2FB', '#89E4FB ', '#7CFCB4', '#FDF881', '#FBC093', '#F99FA0',
        '#F99D85', '#3EBFB9', '#5B9FFC', '#A045BF', '#BC5759', '#3A7CBE', '#A5A5A5', '#000000'
    ]);
    const hsv = reactive({
        h: 0,
        s: 1,
        v: 1
    });


    const toolbarConfig = {
        excludeKeys: ["uploadVideo", "fullScreen"],
    };
    const editorConfig = ref({
        placeholder: "请输入内容详情...",
        MENU_CONF: {} 
    });

    const handleCreated = (editor) => {
        editorRef.value = editor;
    };

    const politicsStyle = computed(() => ({
        width: `50%`,
        transform: `translateX(${politics.value * 100}%)`
    }));

    const selectPresetColor = (color) => {
        selectedColor.value = color;
        hexInput.value = color;
        const newHsv = hexToHsv(color);
        Object.assign(hsv, newHsv);
    }
    const hsvToHex = (h, s, v) => {
        h = h % 360;
        const C = v * s;
        const X = C * (1 - Math.abs((h / 60) % 2 - 1));
        const m = v - C;
        
        let r, g, b;
        
        if (h >= 0 && h < 60) [r, g, b] = [C, X, 0];
        else if (h >= 60 && h < 120) [r, g, b] = [X, C, 0];
        else if (h >= 120 && h < 180) [r, g, b] = [0, C, X];
        else if (h >= 180 && h < 240) [r, g, b] = [0, X, C];
        else if (h >= 240 && h < 300) [r, g, b] = [X, 0, C];
        else [r, g, b] = [C, 0, X];
        
        return `#${[r + m, g + m, b + m]
            .map(x => Math.round(x * 255).toString(16).padStart(2, '0'))
            .join('')}`;
    }
    const hexToHsv = (hex) => {
        hex = hex.replace('#', '');
        if (hex.length === 3) {
            hex = hex.split('').map(x => x + x).join('');
        }
        
        const r = parseInt(hex.substring(0, 2), 16) / 255;
        const g = parseInt(hex.substring(2, 4), 16) / 255;
        const b = parseInt(hex.substring(4, 6), 16) / 255;
        
        const max = Math.max(r, g, b);
        const min = Math.min(r, g, b);
        const delta = max - min;
        
        let h = 0;
        if (delta !== 0) {
            if (max === r) h = ((g - b) / delta) % 6;
            else if (max === g) h = (b - r) / delta + 2;
            else h = (r - g) / delta + 4;
            h = Math.round(h * 60);
            if (h < 0) h += 360;
        }
        
        const s = max === 0 ? 0 : delta / max;
        const v = max;
        
        return { h, s, v };
    }
    const emit = defineEmits(['update-show-visable'])
    const backIndex = () => {
        emit('update-show-visable', false);
    }
    onBeforeUnmount(() => {
        if (!editorRef.value) return;
        editorRef.value.destroy();
    });
</script>
<style>
    .point-list .el-button{width: 50%;margin: 0 auto;border: 1px solid #1465E1;color: #1465E1;}
    .point-list .el-button:hover{border: 1px solid #1465E1;color: #1465E1;}
    .desc-item .el-scrollbar__wrap { overflow-x: hidden !important; }
    .submit .el-button{width: 30%;}
    .submit .el-button.save{color: #fff;}
    .graph-box.el-popper.is-light, .el-popper.is-light>.el-popper__arrow:before{border: 1px solid #2E7CF4;box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.15);padding: 0;}
    .color-box .el-input{width: 30%;margin-left: 10px;}
</style>
<style scoped>
    .info-box{background: #FFFFFF;width: calc(100% - 40px);padding:10px 0 40px 0;position: relative;}
    .top-box{display: flex;flex-direction: row;margin-left: 20px;justify-content: end;padding-bottom: 10px;align-items: center;gap: 20px;}
    .full-screen{display: flex;flex-direction: row;align-items: center;margin-right: 40px;}
    .full-screen img{width: 25px;height: 25px;cursor: pointer;}
    .full-screen span{margin-left: 5px;font-family: 微软雅黑, Microsoft YaHei, SimSun;font-size: 14px;cursor: pointer;}
    .know-box{display: flex;flex-direction: row;justify-content: space-between;}
    .left-box{background: linear-gradient( 135deg, #2E7CF4 0%, #0457D5 100%);width: 200px;margin-left: 40px;margin-top: 20px;border-radius: 10px;display: flex;flex-direction: row;align-items: center;position: absolute;top: 20%;left: 40px;}
    .left-box .point-box{width: 100%;background: #fff;border-radius: 10px;margin-top: 5px;margin-bottom: 10px;margin-left: 1px;margin-right: 1px;}
    .left-box .point-list{padding: 20px 0 20px 0;font-family: 微软雅黑, Microsoft YaHei, SimSun;display: flex;flex-direction: row;justify-content: space-around;font-weight: 600;}
    .left-box .point-list:first-child{margin-top: 10px;}
    .right-box{background: linear-gradient( 135deg, #2E7CF4 0%, #0457D5 100%);width: 200px;margin-left: 40px;border-radius: 10px;display: flex;flex-direction: row;align-items: center;position: absolute;top: 20%;right: 40px;}
    .right-box .point-box{width: 100%;background: #fff;border-radius: 10px;margin-top: 5px;margin-bottom: 10px;margin-left: 1px;margin-right: 1px;}
    .right-box .point-list{padding: 20px 0 20px 0;font-family: 微软雅黑, Microsoft YaHei, SimSun;display: flex;flex-direction: row;justify-content: space-around;font-weight: 600;}
    .menu-box{background: linear-gradient( 135deg, #2E7CF4 0%, #0457D5 100%);width: 300px;margin: 20px auto;border-radius: 10px;height: 54px;display: flex;align-items: center;}
    .menu-box .menu-div{display: flex;flex-direction: row;gap: 20px;margin: 1px;justify-content: center;background: white;height: 50px;width: 100%;border-radius: 10px;align-items: center;}
    .menu-item{cursor: pointer;}
    .menu-item img{width: 35px;height: 35px;}
    .desc-item{width: 400px!important;top: 10%;}
    .desc-item .point-list{width: 90%;margin: 0 auto;flex-direction: column;padding: 10px 0 0 10px;}
    .desc-title{font-family: 微软雅黑, Microsoft YaHei, SimSun;text-align: left;padding: 20px 0 0 20px;font-size: 16px;font-weight: 600;}
    .point-list .items{ display: flex;flex-direction: row;align-items: center; }
    .point-list .items .reds{ color: red;margin-left: 5px; }
    .point-list .items .text{ font-family: 微软雅黑, Microsoft YaHei, SimSun;font-size: 14px; }
    .point-list .inputs{ margin-top: 10px; }
    .chapter-icon{width: 50px!important;background: linear-gradient( 135deg, #2E7CF4 0%, #0457D5 100%)!important;border-radius: 50px;padding: 5px 10px 5px 10px;font-family: 微软雅黑, Microsoft YaHei, SimSun;font-size: 12px;}
    .chapter-icon.orange{background: linear-gradient( 135deg, #D4A51D 0%, #D4721D 100%)!important;}
    .points{display: flex;flex-direction: row;gap: 10px;margin-top: 10px;color: #fff;text-align: center;}
    .class-switch{position: relative;}
    .class-switch .switch-item { cursor: pointer; position: relative; transition: color 0.3s ease; text-align: center; color: #7f8c8d;z-index: 2;font-family: 微软雅黑, Microsoft YaHei, SimSun;font-size: 12px; }
    .slider { border-radius: 35px; height: 35px; background: #3869E7; z-index: 1; transition: transform 0.4s cubic-bezier(0.68, -0.55, 0.27, 1.55); position: absolute; top: 0; }
    .switch-item.active { color: white; }
    .mode-1 { background: #1465E1; }
    .mode-2 { background: #1465E1; }
    .class-switch{display: flex;flex-direction: row;width: 40%;background: #F7F7F7;border-radius: 40px;margin-top: 10px;}
    .class-switch .switch-item{width: 50%;height: 35px;line-height: 35px;}
    .desc-title{display: flex;flex-direction: row;align-items: center;}
    .desc-title .points{margin-left: 10px;margin-top: 0px;}
    .point-list .desc{font-size: 14px;font-weight: 400;font-family: 微软雅黑, Microsoft YaHei, SimSun;text-align: left;margin-top: 10px;display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; overflow: hidden; text-overflow: ellipsis;color: #BABBBE;}
    .desc-table{padding-bottom: 20px;margin-top: 10px;}
    .desc-table .table-item{display: flex;flex-direction: row;justify-content: space-around;width: 100%;margin: 0 auto;padding: 10px 0px 10px 0px;}
    .desc-table .table-item:nth-child(odd) { background-color: #E9F0FD; }
    .desc-table .table-item:nth-child(even) { background-color: #F4F8FE; } 
    .desc-table .table-item:hover { background-color: #e6f7ff; transition: background-color 0.3s ease; }
    .desc-table .table-item .left{margin-left: 10px;}
    .desc-table .table-item .right{margin-right: 10px;}
    .desc-table .table-item.tab-content{font-size: 14px;font-weight: 400;font-family: 微软雅黑, Microsoft YaHei, SimSun;color: #BABBBE;}
    .desc-box{padding-bottom: 30px;}
    .notices{background: #F8FAFE;width: 90%;margin-top: 10px;padding-bottom: 20px;}
    .top-notice{display: flex;flex-direction: row;padding: 10px 0 0 10px;align-items: center;}
    .top-notice img{width: 24px;}
    .top-notice span{font-family: 微软雅黑, Microsoft YaHei, SimSun;margin-left: 6px;font-size: 14px;color: #DB9333;border-bottom: 2px solid #000;}
    .notice-content{display: flex;flex-direction: column;align-items: start;font-family: 微软雅黑, Microsoft YaHei, SimSun;padding: 20px 0 0 10px;}
    .submit{display: flex;flex-direction: row!important;margin-top: 20px!important;}
    .headers{display: flex;flex-direction: row;justify-content: start;align-items: center;}
    .headers img{width: 15px;}
    .headers span{margin-left: 5px;font-family: 微软雅黑, Microsoft YaHei, SimSun;font-size: 14px;}
    .dialog-content{min-height: 50px;display: flex;flex-direction: row;align-items: center;justify-content: center;}
    .popover-box{text-align: center;}
    .popover-box span{display: block;cursor: pointer;width: 100%;padding: 10px 0 10px 0;}
    .popover-box span:hover{ background: rgb(8, 90, 215,0.1); }
    .color-box{display: flex;flex-direction: row;justify-content: center;align-items: center;}
    .color-box span{font-size: 14px;font-weight: 400;font-family: 微软雅黑, Microsoft YaHei, SimSun;}
    .color-box span{font-size: 14px;font-weight: 400;font-family: 微软雅黑, Microsoft YaHei, SimSun;}

    .preset-colors { display: grid; grid-template-columns: repeat(8, 1fr); gap: 10px; margin-bottom: 20px; }
    .color-block { position: relative;width: 30px; height: 30px; border-radius: 30px; cursor: pointer; box-shadow: 0 1px 3px rgba(0,0,0,0.2); }
    .color-check { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);border: 2px solid #0457D5;width: 34px; height: 34px;border-radius: 30px;box-shadow: 0 1px 3px #0457D5; }

    .graph-container { width: 100%; min-height: 750px; border: 1px solid #eee; overflow: hidden;padding-bottom: 40px; }
    .selected-ring { transform-box: fill-box; transform-origin: center; animation: rotate 6s linear infinite; }
    .link { cursor: pointer; }
    select { margin: 10px; padding: 5px; font-size: 16px; z-index: 1000; position: relative; }
    @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
    .back-btn{display: block;width: 60px;height: 30px;color: #fff;background: #1465E1;text-align: center;line-height: 30px;font-family: 微软雅黑, Microsoft YaHei, SimSun;font-size: 12px;border-radius: 4px;cursor: pointer;margin-left: 20px;}
</style>